﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using élénkPróbája.attributes;
using élénkPróbája.Test.extention;
using élénkPróbája.validators;

namespace élénkPróbája.Test
{
    [TestClass]
    public class AttributedValidatorFactoryTester
    {
        private readonly ValidatorAttributeFactory factory;

        public AttributedValidatorFactoryTester()
        {
            factory = new ValidatorAttributeFactory();
        }
        [TestMethod]
        public void Should_instantiate_validator()
        {
            var validator = factory.GetValidator<AttributedPerson>();
            validator.ShouldBe<TestValidator>();
        }
        [TestMethod]
        public void Should_instantiate_validator_non_generic()
        {
            var validator = factory.GetValidator(typeof(AttributedPerson));
            validator.ShouldBe<TestValidator>();
        }
        [TestMethod]
        public void Should_return_null_when_null_is_passed_to_GetValidator()
        {
            factory.GetValidator((Type)null).ShouldBeNull();
        }

        [TestMethod]
        public void Should_return_null_when_type_has_no_attribute()
        {
            factory.GetValidator<NonAttributedPerson>().ShouldBeNull();
        }

        [TestMethod]
        public void Should_return_null_when_attribute_has_no_type()
        {
            factory.GetValidator<AttributedPersonWithNoType>().ShouldBeNull();
        }
        [TestMethod]
        public void Should_instantiate_parameter_validator()
        {
            var parameter = GetTestParameters().First(p => p.Name == "attributedArgument");
            var validator = factory.GetValidator(parameter);
            validator.ShouldBe<TestValidator>();
        }
        [TestMethod]
        public void Should_return_null_when_parameter_null_is_passed_to_GetValidator()
        {
            factory.GetValidator((ParameterInfo)null).ShouldBeNull();
        }
        [TestMethod]
        public void Should_return_null_when_parameter_has_no_attribute()
        {
            var parameter = GetTestParameters().First(p => p.Name == "nonAttributedArgument");
            factory.GetValidator(parameter).ShouldBeNull();
        }
        [TestMethod]
        public void Should_return_null_when_parameter_attribute_has_no_type()
        {
            var parameter = GetTestParameters().First(p => p.Name == "attributedArgumentWithNoType");
            factory.GetValidator(parameter).ShouldBeNull();
        }

        private static IList<ParameterInfo> GetTestParameters()
        {
            return typeof(SomeService).GetMethod("SomeMethod").GetParameters();
        }
        #region InternalClasses

        [Validator(typeof(TestValidator))]
        private class AttributedPerson
        {
        }

        private class NonAttributedPerson
        {
        }

        [Validator(null)]
        private class AttributedPersonWithNoType
        {
        }

        private class TestValidator : AbstractValidator<AttributedPerson>
        {
        }

        private class SomeService
        {
            public void SomeMethod(
                [Validator(typeof(TestValidator))] string attributedArgument,
                [Validator(null)] string attributedArgumentWithNoType,
                string nonAttributedArgument
            )
            {
            }
        }
#endregion InternalClasses

    }
}
